#include "ns3/core-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/network-module.h"
#include "ns3/applications-module.h"
#include "ns3/wifi-module.h"
#include "ns3/mobility-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"
#include "ns3/netanim-module.h"

#include <iostream>
#include <cstdint>

using namespace ns3;
NS_LOG_COMPONENT_DEFINE("adhocnet");

int main(){

	uint32_t n=6;
	NodeContainer nodes;
	nodes.Create(n);
	
	// set default channel and phy model
	YansWifiChannelHelper channel=YansWifiChannelHelper::Default();
	YansWifiPhyHelper phy=YansWifiPhyHelper::Default();
	phy.SetChannel(channel.Create());
	
	WifiHelper wifi;
	wifi.SetStandard(WIFI_PHY_STANDARD_80211a);
	wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
		"DataMode",StringValue("OfdmRate6Mbps")
	);
	
	// set mac type
	WifiMacHelper mac;
	mac.SetType("ns3::AdhocWifiMac","Slot",StringValue("0.1s"));
	NetDeviceContainer node_dev=wifi.Install(phy,mac,nodes);
	
	// set mobility model
	MobilityHelper mobility;
	mobility.SetPositionAllocator(
		"ns3::GridPositionAllocator",
		"MinX",DoubleValue(0.0),
		"MinY",DoubleValue(0.0),
		"DeltaX",DoubleValue(5.0),
		"DeltaY",DoubleValue(5.0),
		"GridWidth",UintegerValue(10),
		"LayoutType",StringValue("RowFirst")
	);
	mobility.SetMobilityModel(
		"ns3::RandomWalk2dMobilityModel",
        	"Bounds",RectangleValue(Rectangle(-50,50,-50,50))
	);
	mobility.Install(nodes);

	// TCP/IP
	InternetStackHelper stack;
	stack.Install(nodes);

	Ipv4AddressHelper addr;
	addr.SetBase("10.1.1.0","255.255.255.0");
	Ipv4InterfaceContainer interface=addr.Assign(node_dev);

	// OnOff app
	uint16_t port=9999;
	OnOffHelper onoff(
		"ns3::TcpSocketFactory",
		Address(InetSocketAddress(interface.GetAddress(0),port))
	);
	onoff.SetAttribute("OnTime",StringValue("ns3::ConstantRandomVariable[Constant=1]"));
	onoff.SetAttribute("OffTime",StringValue("ns3::ConstantRandomVariable[Constant=0]"));
	ApplicationContainer app0=onoff.Install(nodes);
	app0.Start(Seconds(1.0));
	app0.Stop(Seconds(15.0));
	
	PacketSinkHelper sink(
		"ns3::TcpSocketFactory",
		Address(InetSocketAddress(Ipv4Address::GetAny(),port))
	);
	
	ApplicationContainer app1=sink.Install(nodes.Get(0));
	app1.Start(Seconds(1.0));
	app1.Stop(Seconds(15.0));
	
	Ipv4GlobalRoutingHelper::PopulateRoutingTables();
	Simulator::Stop(Seconds(15.0));
	
	// generate xml and trace data
	phy.EnablePcap("adhoc",node_dev.Get(0));
	AnimationInterface anim("adhocnet.xml");
	AsciiTraceHelper asciitracer;
	phy.EnableAsciiAll(asciitracer.CreateFileStream("adhocnet.tr"));

	Simulator::Run();
	Simulator::Destroy();
	return 0;
}
